// services/auth.service.ts

import axios, { AxiosError, type InternalAxiosRequestConfig } from 'axios';

// --- WebView2 类型定义 ---
/**
 * 为 TypeScript 添加 WebView2 的 postMessage API 类型定义。
 * 将此代码块放在 .ts 文件的顶部 (import 之后)。
 */
declare global {
  interface Window {
    chrome?: {
      webview?: {
        /**
         * 将消息从 Web 内容发送到主机应用程序。
         * @param message 可以是字符串或可序列化为 JSON 的对象。
         */
        postMessage(message: any): void;
      };
    };
  }
}

// ----------------------------------------------------------------------------
// 配置
// ----------------------------------------------------------------------------

/**
 * 您的 Web API 服务器的基地址
 */
const API_BASE_URL: string = document.location.origin; // 请修改为您的实际后端地址

/**
 * 用于在 localStorage 中存储 access_token 的键名
 */
export const TOKEN_STORAGE_KEY: string = 'access_token';
export const USER_NAME_STORAGE_KEY: string = 'userName';

// ----------------------------------------------------------------------------
// 2. 类型定义 (Interface)
// ----------------------------------------------------------------------------

/**
 * 默认 /Token 端点成功时返回的 JSON 结构
 */
interface TokenResponse {
  access_token: string;
  token_type: string; // 通常是 "bearer"
  expires_in: number; // Token 有效期 (秒), 例如 86399 (24小时)
  userName: string;
  // Owin 默认模板还会包含这两个
  '.issued'?: string;
  '.expires'?: string;
}

/**
 * 默认 /api/Account/UserInfo 端点返回的 JSON 结构
 * (对应 AccountController.cs 中的 UserInfoViewModel)
 */
interface UserInfoViewModel {
  Id: string,
  Username: string;
  Fullname: string;
  Roles: string[];
  HasRegistered: boolean;
  LoginProvider: string | null;
}

/**
 * /Token 端点失败时返回的 JSON 结构
 */
interface TokenErrorResponse {
  error: string; // 例如 "invalid_grant"
  error_description: string; // 例如 "用户名或密码不正确。"
}

// ----------------------------------------------------------------------------
// 3. 核心认证函数
// ----------------------------------------------------------------------------

/**
 * 执行登录
 * @param username 用户的 Email 或用户名
 * @param password 用户的密码
 * @returns Promise<boolean> - 登录是否成功
 */
export async function login(username: string, password: string): Promise<boolean> {
  // 1. 准备表单数据 (x-www-form-urlencoded)
  // 这是 Owin OAuth 服务器的严格要求
  const params = new URLSearchParams();
  params.append('grant_type', 'password'); // 必须
  params.append('username', username);
  params.append('password', password);

  try {
    // 2. 发送 POST 请求到 /Token 端点
    const response = await axios.post<TokenResponse>(
      `${API_BASE_URL}/Token`,
      params, // Axios 会自动处理 URLSearchParams
      {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
      }
    );
    
    // 3. 登录成功，获取 Token
    const accessToken = response.data.access_token;
    if (!accessToken) {
      console.error('登录失败: 未从服务器获取到 access_token');
      return false;
    }
    console.log(accessToken, accessToken)
    // 4. 将 Token 存储在 localStorage
    localStorage.setItem(TOKEN_STORAGE_KEY, accessToken);
    localStorage.setItem(USER_NAME_STORAGE_KEY, response.data.userName);
    console.log('登录成功');
    
    return true;
  } catch (err) {
    // 5. 登录失败 (使用类型守卫处理错误)
    handleAuthError(err, '登录失败');
    localStorage.removeItem(TOKEN_STORAGE_KEY);
    return false;
  }
}

/**
 * 退出登录
 */
export function logout(): void {
  // 1. 从 localStorage 清除 Token
  localStorage.removeItem(TOKEN_STORAGE_KEY);

  // 2. (如果设置了) 清理 axios 默认头部
  delete axios.defaults.headers.common['Authorization'];

  // 3. (可选) 在这里添加重定向到登录页的逻辑
  // window.location.href = '/login';
  console.log('已退出登录');
}

/**
 * 获取当前存储的 Access Token
 * @returns string | null
 */
export function getAccessToken(): string | null {
  return localStorage.getItem(TOKEN_STORAGE_KEY);
}

// ----------------------------------------------------------------------------
// 5. 调用受保护的 API (示例)
// ----------------------------------------------------------------------------

/**
 * 示例：获取受保护的当前用户信息
 * (调用 AccountController 的 UserInfo)
 */
export async function fetchUserInfo(): Promise<UserInfoViewModel | null> {
  try {
    // 拦截器会自动添加 'Authorization: Bearer ...'
    const response = await apiClient.get<UserInfoViewModel>(
      `/api/Account/UserInfo`
    );
    return response.data;
  } catch (err) {
    handleAuthError(err, '获取用户信息失败');
    
    // 如果是 401 (未授权), 可能意味着 Token 过期了
    if (axios.isAxiosError(err) && err.response?.status === 401) {
       // 既然没有 Refresh Token, 我们只能强制用户登出
       console.warn('Token 已失效或未授权, 正在退出登录...');
       logout();
    }
    
    return null;
  }
}

// ----------------------------------------------------------------------------
// 6. 辅助工具
// ----------------------------------------------------------------------------

/**
 * 统一的错误处理器
 */
function handleAuthError(err: unknown, contextMessage: string): void {
  let errorMessage = '未知错误';
  if (axios.isAxiosError(err)) {
    // 尝试解析 Owin 返回的错误
    const responseData = err.response?.data as TokenErrorResponse;
    if (responseData?.error_description) {
      errorMessage = responseData.error_description;
    } else {
      errorMessage = err.message;
    }
  } else if (err instanceof Error) {
    errorMessage = err.message;
  }
  
  console.error(`${contextMessage}: ${errorMessage}`);
}

/**
 * 从 localStorage 清除 Access Token
 */
export function clearToken(): void {
  localStorage.removeItem(TOKEN_STORAGE_KEY);
}

// ----------------------------------------------------------------------------
// 3. 创建 Axios 实例
// ----------------------------------------------------------------------------

const apiClient = axios.create({
  baseURL: API_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

// ----------------------------------------------------------------------------
// 4. 请求拦截器 (Request Interceptor)
// ----------------------------------------------------------------------------

apiClient.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    // 检查是否是登录请求 (/Token)
    // 我们不为 /Token 请求附加 Authorization 头部
    if (config.url === '/Token') {
      return config;
    }

    // 1. 从 localStorage 获取 token
    const token = getAccessToken();

    // 2. 如果 token 存在, 附加到 Authorization 头部
    if (token && config.headers) {
      config.headers['Authorization'] = `Bearer ${token}`;
    }

    return config;
  },
  (error: AxiosError) => {
    // 处理请求错误
    return Promise.reject(error);
  }
);

// ----------------------------------------------------------------------------
// 5. 响应拦截器 (Response Interceptor) - 核心逻辑
// ----------------------------------------------------------------------------

apiClient.interceptors.response.use(
  // 1. 状态码为 2xx 时的处理
  (response) => {
    // 任何 2xx 状态码都会触发此函数
    // 直接返回响应
    return response;
  },

  // 2. 状态码非 2xx 时的处理 (例如 401)
  (error: AxiosError) => {
    // 任何非 2xx 状态码都会触发此函数

    // 检查是否有响应体
    if (!error.response) {
      console.error('网络错误或服务器未响应:', error.message);
      return Promise.reject(error);
    }

    // *** 核心：处理 401 Unauthorized ***
    if (error.response.status === 401) {
      // 检查请求的 URL 是否是登录页面
      // 如果是 /Token 失败 (密码错误), 我们不应跳转, 而应让登录页面处理
      if (error.config?.url === '/Token') {
        console.warn('登录 /Token 失败 (401)，不执行跳转。');
        return Promise.reject(error);
      }
      
      // 检查是否已在登录页, 防止无限重定向
      if (window.location.pathname !== '/login') {
        console.error('未授权 (401) 或 Token 已过期，正在跳转到登录页...');
        
        // 1. 清除无效的 Token
        clearToken();

        // 2. 执行跳转
        //    (注意: 这会强制刷新页面, 清空所有 Vue/Pinia 状态)
        window.location.href = '/login'; 
        
        // 备注: 如果您使用 Vue Router, 更好的方式是导入 router 实例
        // import router from '@/router'; // (这可能导致循环依赖)
        // router.push('/login');
        // 但 window.location.href 是最简单且可靠的
      }
    }

    // 对于 401 之外的其他错误 (例如 404, 500, 403), 
    // 我们只是将错误传递下去，让调用它的 .catch() 去处理
    return Promise.reject(error);
  }
);

/**
 * 默认导出配置好的 Axios 实例
 */
export default apiClient;

/**
 * [Admin] GET /api/Account/GetUsers 的响应模型
 */
export interface AdminUserViewModel {
  Id: string;
  UserName: string;
  Email: string;
  FullName: string;
  IsLockedOut: boolean;
  Roles: string[];
}

/**
 * [Admin] POST /api/Account/CreateUser 的请求模型
 */
export interface AdminCreateUserModel {
  Email: string;
  UserName: string;
  Password: string;
  FullName?: string; // 可选
  Roles?: string[]; // 可选
}

/**
 * [Admin] PUT /api/Account/UpdateUser/{id} 的请求模型
 */
export interface AdminUpdateUserModel {
  Email: string;
  FullName?: string;
  PhoneNumber?: string;
  Roles?: string[];
}

/**
 * [Admin] POST /api/Account/ResetPassword 的请求模型
 */
export interface AdminResetPasswordModel {
  UserId: string;
  NewPassword: string;
}

/**
 * ASP.NET Identity 验证错误 (400 Bad Request) 的标准响应结构
 */
export interface IdentityErrorResponse {
  Message: string;
  ModelState: {
    [key: string]: string[];
  };
}

/**
 * [Admin] GET /api/Account/GetUsers 的分页请求参数
 */
export interface PagingParams {
  pageNumber: number;
  pageSize: number;
}

/**
 * [Admin] 通用分页响应结构 (匹配 C# PagedResultViewModel<T>)
 */
export interface PagedResult<T> {
  CurrentPage: number;
  PageSize: number;
  TotalCount: number;
  TotalPages: number;
  Data: T[];
}

// ----------------------------------------------------------------------------
// 2. Admin API 调用方法
// ----------------------------------------------------------------------------

/**
 * [Admin] 获取所有用户的列表 (支持分页)
 * @param params 分页参数 { pageNumber, pageSize }
 * @returns 分页后的用户列表
 * @throws AxiosError - 失败时 (401 会被拦截器处理, 403/500 会抛出)
 */
export async function getUsers(
  params: PagingParams
): Promise<PagedResult<AdminUserViewModel>> {
  
  // 1. 使用 apiClient, 并通过 'params' 选项传递分页参数
  //    Axios 会自动将其序列化为 ?pageNumber=1&pageSize=10
  const response = await apiClient.get<PagedResult<AdminUserViewModel>>(
    '/api/Account/GetUsers',
    {
      params: {
        pageNumber: params.pageNumber,
        pageSize: params.pageSize
      }
    }
  );

  // 2. 返回完整的 data 对象 (现在是 PagedResult)
  return response.data;
}

/**
 * [Admin] 创建一个新用户
 * @param model 用户创建信息
 * @throws AxiosError<IdentityErrorResponse> - 失败时 (例如验证失败)
 */
export async function createUser(model: AdminCreateUserModel): Promise<void> {
  // 成功时返回 2xx, 失败时 (400/500) 抛出 AxiosError
  await apiClient.post('/api/Account/CreateUser', model);
}

/**
 * [Admin] 更新一个用户信息
 * @param id 目标用户的 ID
 * @param model 要更新的信息
 * @throws AxiosError<IdentityErrorResponse> - 失败时
 */
export async function updateUser(
  id: string,
  model: AdminUpdateUserModel
): Promise<void> {
  await apiClient.put(`/api/Account/UpdateUser/${id}`, model);
}

/**
 * [Admin] 删除一个用户
 * @param id 目标用户的 ID
 * @throws AxiosError - 失败时
 */
export async function deleteUser(id: string): Promise<void> {
  await apiClient.delete(`/api/Account/DeleteUser/${id}`);
}

/**
 * [Admin] 重置指定用户的密码
 * @param model 包含 UserId 和 NewPassword
 * @throws AxiosError<IdentityErrorResponse> - 失败时
 */
export async function resetPassword(
  model: AdminResetPasswordModel
): Promise<void> {
  await apiClient.post('/api/Account/ResetPassword', model);
}

/**
 * [Admin] 解除用户锁定
 * @param id 目标用户的 ID
 * @throws AxiosError - 失败时
 */
export async function unlockUser(id: string): Promise<void> {
  // API 期望一个空的 POST
  await apiClient.post(`/api/Account/UnlockUser/${id}`);
}

/**
 * [Admin] GET /api/Account/GetRoles 的响应模型
 */
export interface RoleViewModel {
  Id: string;
  Name: string;
}


// ... (保留所有现有函数: getUsers, createUser, updateUser, deleteUser, ...)


/**
 * [Admin] 获取所有角色的列表
 * @returns 角色列表
 * @throws AxiosError - 失败时
 */
export async function getRoles(): Promise<RoleViewModel[]> {
  const response = await apiClient.get<RoleViewModel[]>(
    '/api/Account/GetRoles'
  );
  return response.data;
}

/**
 * 辅助函数：从 Axios 错误中解析 Identity 验证消息
 * @param error 捕获到的 AxiosError
 * @returns 一个格式化的错误字符串
 */
export function getApiError(error: unknown): string {
  if (axios.isAxiosError(error)) {
    const axiosError = error as AxiosError<IdentityErrorResponse>;
    const data = axiosError.response?.data;
    
    if (data?.ModelState) {
      // 收集所有模型验证错误
      return Object.values(data.ModelState).flat().join('\n');
    }
    if (data?.Message) {
      return data.Message;
    }
    return axiosError.message;
  }
  return '发生了未知错误';
}

// 使用示例：
// 获取用户列表
// const fetchUsers = async () => {
//   loading.value = true;
//   error.value = null;
//   try {
//     users.value = await getUsers();
//   } catch (err) {
//     // 401 会被拦截器处理 (跳转), 这里捕获 403 或 500
//     error.value = `加载用户失败: ${getApiError(err)}`;
//   } finally {
//     loading.value = false;
//   }
// };